package br.com.gr.jcash.ctr;

import br.com.gr.jcash.util.JsfUtil;
import br.com.gr.jcash.util.PaginationHelper;
import br.com.gr.jcash.dmp.Conta;
import br.com.gr.jcash.dmp.TipoCategoria;
import br.com.gr.jcash.exception.JCashException;
import br.com.gr.jcash.iface.ICategoriaBO;
import br.com.gr.jcash.iface.IContaBO;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.inject.Named;

@Named(value = "contaController")
@SessionScoped
public class ContaController implements Serializable {

    @EJB
    private IContaBO bo;
    @EJB
    private ICategoriaBO categoriaBO;
    private Conta current;
    private DataModel itens = null;
    private PaginationHelper pagination;
    private int selectedItemIndex;
    private String LIST = "list";
    private String CREATE = "create";
    private String VIEW = "view";
    private String EDIT = "edit";
    private List<SelectItem> selectCategoria;

    public ContaController() {
    }

    public Conta getSelected() {
        if (current == null) {
            current = new Conta();
            selectedItemIndex = -1;
        }
        return current;
    }

    public void setSelected(Conta conta) {
        this.current = conta;
    }

    private IContaBO getFacade() {
        return bo;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(7) {
                @Override
                public int getItemsCount() {
                    try {
                        return getFacade().count().intValue();
                    } catch (JCashException ex) {
                        Logger.getLogger(ContaController.class.getName()).log(Level.SEVERE, null, ex);
                        return 0;
                    }
                }

                @Override
                public DataModel createPageDataModel() {
                    try {
                        return new ListDataModel(getFacade().buscarPorFaixa(new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
                    } catch (JCashException ex) {
                        Logger.getLogger(ContaController.class.getName()).log(Level.SEVERE, null, ex);
                        return null;
                    }
                }
            };
        }
        return pagination;
    }

    public String prepareList() {
        recreateModel();
        return LIST;
    }

    public String prepareView() {
        current = (Conta) getItens().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItens().getRowIndex();
        return VIEW;
    }

    public String prepareCreate() {
        current = new Conta();
        selectedItemIndex = -1;
        return CREATE;
    }

    public String create() {
        try {
            getFacade().criar(current);
            JsfUtil.addSuccessMessage("Registro criado");
            return prepareCreate();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, "Erro na persistência");
            return null;
        }
    }

    public String prepareEdit() {
        current = (Conta) getItens().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItens().getRowIndex();
        return EDIT;
    }

    public String prepareEditFromView() {
        return EDIT;
    }

    public String update() {
        try {
            current = getFacade().editar(current);
            JsfUtil.addSuccessMessage("Registro alterado");
            return VIEW;
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, "Erro na persistência");
            return null;
        }
    }

    public String destroy() {
        current = (Conta) getItens().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItens().getRowIndex();
        performDestroy();
        recreatePagination();
        recreateModel();
        return LIST;
    }

    public String destroyAndView() throws JCashException {
        performDestroy();
        recreateModel();
        updateCurrentItem();
        if (selectedItemIndex >= 0) {
            return VIEW;
        } else {
            // all items were removed - go back to list
            recreateModel();
            return LIST;
        }
    }

    private void performDestroy() {
        try {
            getFacade().remover(current);
            JsfUtil.addSuccessMessage("Registro excluído");
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, "Erro a persistência");
        }
    }

    private void updateCurrentItem() throws JCashException {
        int count = getFacade().count().intValue();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            if (pagination.getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().buscarPorFaixa(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
        }
    }

    public DataModel getItens() {
        if (itens == null) {
            itens = getPagination().createPageDataModel();
        }
        return itens;
    }

    private void recreateModel() {
        itens = null;
    }

    private void recreatePagination() {
        pagination = null;
    }

    public String next() {
        getPagination().nextPage();
        recreateModel();
        return LIST;
    }

    public String previous() {
        getPagination().previousPage();
        recreateModel();
        return LIST;
    }

    public SelectItem[] getItemsAvailableSelectMany() throws JCashException {
        return JsfUtil.getSelectItems(bo.buscarTodos(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() throws JCashException {
        return JsfUtil.getSelectItems(bo.buscarTodos(), true);
    }

    public String getNomeEntidade() {
        return "Conta";
    }

    public List<SelectItem> getSelectCategoria() {
        if (selectCategoria == null) {
            selectCategoria = new ArrayList<>();
            recreateSelectCategoria();
        }
        return selectCategoria;
    }

    private void recreateSelectCategoria() {
        try {
            selectCategoria = JsfUtil.getSelectItemsGroupCategoria(categoriaBO.buscarTodos(), true);
        } catch (JCashException ex) {
            Logger.getLogger(ContaController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void limparDadosIniciaisContaCapital(AjaxBehaviorEvent event) throws AbortProcessingException {
        if (getSelected().getCategoria().getCatTipo() != TipoCategoria.C) {
            getSelected().setCtaDataInicial(null);
            getSelected().setCtaSaldoInicial(BigDecimal.ZERO);
            JsfUtil.addWarningMessage("Saldo inicial e data somente para contas de capital!");
        }
    }

    public IContaBO getBo() {
        return bo;
    }
}
